import numpy as np
import pymysql
import psycopg2
from psycopg2 import sql
import locale

print(locale.getpreferredencoding())  # Windows中文版通常显示'cp936'(GBK)


def convert_encoding(encoding):
    """
    转换人脸编码格式：
    - 如果输入是NumPy数组，返回适合存入数据库的字符串格式。
    - 如果输入是字符串格式，返回对应的NumPy数组。

    :param encoding: 输入的人脸编码，可以是NumPy数组或字符串
    :return: 转换后的结果，可能是NumPy数组或字符串
    """
    if isinstance(encoding, np.ndarray):
        # 将NumPy数组转换为字符串，这里使用逗号作为分隔符
        return ",".join(map(str, encoding.flatten()))
    elif isinstance(encoding, str):
        # 将字符串转换回NumPy数组
        # 假设字符串是以逗号分隔的数值
        try:
            # 使用numpy.fromstring将字符串转换为数组
            array = np.fromstring(encoding, sep=",")
            return array
        except Exception as e:
            raise ValueError(f"无法将字符串转换为NumPy数组: {e}")
    else:
        raise TypeError("输入必须是NumPy数组或字符串")


def insertFace(name, data):
    con = None
    cur = None
    try:
        face = convert_encoding(data)
        con = pymysql.connect(
            host="localhost", port=3306, user="root", passwd="liqian", db="ai"
        )
        cur = con.cursor()
        # 执行插入并提交
        cur.execute("INSERT INTO face (name, face) VALUES (%s, %s)", args=(name, face))
        con.commit()  # 提交事务
    except Exception as e:
        print(f"发生错误: {e}")  # 打印异常信息
    finally:
        # 确保关闭游标和连接，即使发生了异常
        if cur:
            cur.close()
        if con:
            con.close()


# 读取人脸数据
def getFaces():
    try:
        with pymysql.connect(
            host="localhost", port=3306, user="root", passwd="liqian", db="ai"
        ) as con:
            with con.cursor() as cur:
                cur.execute("select * from face")
                # 当你执行了一个查询（例如通过cur.execute("select * from face")），游标对象cur会有一个名为description的属性。这个属性是一个包含描述查询结果集中每个字段信息的元组的列表。每个元组提供关于一个字段的信息，如字段名、类型等。其中，每个元组的第一个元素（即索引为0的位置）是字段名（也就是列名）
                columns = [desc[0] for desc in cur.description]
                rows = cur.fetchall()

                result = [
                    {
                        # zip() 是 Python 内置的一个函数，它用于将多个可迭代对象（如列表、元组等）中的元素配对组合在一起。简单来说，zip() 函数会并行地遍历每个提供的可迭代对象，并从每个对象中取出一个元素组成一个新的元组，直到最短的可迭代对象被耗尽为止
                        **dict(zip(columns, row)),  # ** 解包操作符
                        "face": convert_encoding(row[columns.index("face")]),
                    }
                    for row in rows
                ]

        return result
    except pymysql.MySQLError as e:
        print(f"数据库错误: {e}")
        return []
    except Exception as e:
        print(f"发生错误: {e}")
        return []


# 使用PostgreSQL数据库
# 安装psycopg2库：pip install psycopg2-binary -i https://mirrors.aliyun.com/pypi/simple/


def test():
    conn = psycopg2.connect(
        host="localhost", database="ai", user="postgres", password="liqian"
    )

    cursor = conn.cursor()
    cursor.execute("SELECT * FROM face")
    print(cursor.fetchall())


test()


# 插入postgresql数据库
def postInsertFace(name, data):
    conn = None
    cursor = None
    encoding_list = data.tolist()
    try:
        # PostgreSQL 连接配置
        conn = psycopg2.connect(
            host="localhost",
            port="5432",  # PostgreSQL 默认端口
            user="postgres",  # 默认超级用户
            password="liqian",
            database="ai",
        )

        cursor = conn.cursor()

        # 使用 psycopg2 的 SQL 参数化查询
        query = sql.SQL("INSERT INTO face (name, face) VALUES (%s, %s)")
        cursor.execute(query, (name, encoding_list))

        conn.commit()  # 提交事务
        print("数据插入成功")

    except Exception as e:
        print(f"发生错误: {e}")
        if conn:
            conn.rollback()  # PostgreSQL 需要显式回滚
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()
